<?php
/**
 * PdoHelper
 * @author ming.wang@kunlun-inc.com
 *
 */
class PdoHelper
{
	private $pdo = null;

	protected $tablePrefix = '';

	protected $errorlogPath = '';

	protected $querylogPath = '';

	protected $errorlog = TRUE;

	protected $querylog = TRUE;

	/** 
	 * PdoHelp 构造函数
	 * 
	 * @param array dbConfig 数据库连接的配置
	 * 
	 */
	public function __construct($dbConfig, $logConfig=null)
	{
		$this->pdo = self::pdoConnect($dbConfig, $logConfig);
		$this->errorlogPath = $logConfig['errorlogPath'];

		$this->querylogPath = $logConfig['querylogPath'];
		if(!empty($this->querylogPath))
		$this->errorlog     = $logConfig['errorlog'];

		$this->querylog     = $logConfig['querylog'];

		$this->tablePrefix  = $dbConfig['prefix'];

	}

	public function __destruct()
	{
	}

	/** 
	 * 链接数据库
	 * 
	 * @param dbConfig 数据库配置
	 * 
	 * @return pdo链接
	 */
	public static function pdoConnect($dbConfig, $logConfig = null)
	{
		// 数据库类型
		$pdoDsn      =& $dbConfig['driver'];
		// 数据库服务器地址
		$pdoHost     =& $dbConfig['host'];
		// 数据服务端口
		$pdoPort     =& $dbConfig['port'];
		// 数据库
		$pdoDbname   =& $dbConfig['database'];
		// 数据库连接的用户名
		$pdoUser     =& $dbConfig['login'];
		// 数据库连接的密码
		$pdoPass     =& $dbConfig['password'];
		// 数据库编码
		$pdoEncoding =& $dbConfig['encoding'];
		// 是否开启长连接
		$pdoPersistent =& $dbConfig['Persistent'];
		// 错误处理方式
		$pdoAttrErrmode = isset($dbConfig['pdoAttrErrmode']) 
			? $dbConfig['pdoAttrErrmode']
			: PDO::ERRMODE_SILENT;

		$pdoDsn .= ":host=".$pdoHost.";port=".$pdoPort.";dbname=".$pdoDbname;

		// 连接到数据库
		try {
			return @new PDO($pdoDsn, $pdoUser, $pdoPass, 
				array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES '".$pdoEncoding."';",
				PDO::ATTR_ERRMODE            => $pdoAttrErrmode,
				PDO::ATTR_PERSISTENT         => $pdoPersistent
			)
		);
		} catch (PDOException $e) {
			SysDie('T_DB', 'E_DBCONN');
		}
	}

	/** 
	 * 取得一行记录
	 * 
	 * @param tableName 查询的表名
	 * @param fields    查询的字段
	 * @param where     查询的条件
	 * 
	 * @return 一维数组的结果集
	 */
	public function getRow($tableName, $fields='*', $where='1', $orderBy='')
	{

		$query = "SELECT " . $fields . " FROM " . $tableName . " WHERE " . $where;
		if ($orderBy) {
			$query.= " ORDER BY " .$orderBy;
		}
		$query.= " LIMIT 1";
		$statement = $this->pdo->prepare($query);
		$statement->execute();
		$this->writeLog($query, $statement);
		$statement->setFetchMode(PDO::FETCH_ASSOC);


		return $statement->fetch();
	}

	/** 
	 * 查询多条记录
	 * 
	 * @param tableName  查询的表名
	 * @param fields     查询的字段
	 * @param where      查询的条件
	 * @param orderBy    查询的顺序
	 * @param limit      查询多少条记录
	 * 
	 * @return 结果集，二维数组
	 */
	public function getAll($tableName, $fields='*', $where='1', $orderBy='', $limit='')
	{
		$query = "SELECT " . $fields . " FROM " . $tableName . " WHERE " . $where;
		if ($orderBy) {
			$query .= " ORDER BY " .$orderBy;
		}
		if ($limit) {
			$query .= " LIMIT " . $limit;
		}
		$statement = $this->pdo->prepare($query);
		$statement->execute();
		$this->writeLog($query, $statement);
		$statement->setFetchMode(PDO::FETCH_ASSOC);

		return $statement->fetchAll();
	}

	/**
	 * 删除记录
	 *
	 * @param tableName
	 * @param where
	 *
	 * @return
	 */
	public function delete($tableName, $where='1')
	{
		if ( $where== '1' || empty($where)) {
			//return 0;
		}

		$tableName = $this->tablePrefix . $tableName;

		$query = "DELETE FROM `".$tableName."` WHERE " . $where;
		$statement = $this->pdo->prepare($query);
		$statement->execute();
		$this->writeLog($query, $statement);

		return $statement->rowCount();
	}

	/**
	 * 更新表信息
	 *
	 * @param tableName
	 * @param where
	 *
	 * @return
	 */
	public function update($tableName, $fields=array(), $where='1')
	{
		if (empty($fields) || $where=='1' || empty($where)) {
			return 0;
		}

		$tableName = $this->tablePrefix . $tableName;

		$query = "UPDATE `" . $tableName . "` SET ";
		$sets = '';

		foreach ($fields as $k => $v) {
			$sets.= "`$k`='$v',";
		}

		$query.= substr($sets, 0, strlen($sets)-1);
		$query.= " WHERE " . $where;
		//error_log("query: ".$query ."\n", 3, "/tmp/test.log");
		$statement = $this->pdo->prepare($query);
		$statement->execute();
		//$msg = $statement->errorInfo();
		//$str = var_export($msg,1);
		//error_log($str ."\n", 3, "/tmp/test.log");
		$this->writeLog($query, $statement);

		return $statement->rowCount();
	}

	/**
	 * 插入数据到表
	 *
	 * @param tableName
	 * @param fields
	 *
	 * @return
	 */
	public function insert($tableName, $fields=array())
	{
		if (empty($fields)) {
			return 0;
		}

		$tableName = $this->tablePrefix . $tableName;

		$colName = $colValue = '';
		foreach ($fields as $k => $v) {
			$colName.= "`$k`,";
			$colValue.= "'$v',";
		}
		$colName = substr($colName, 0, strlen($colName)-1);
		$colValue = substr($colValue, 0, strlen($colValue)-1);
		$query = "INSERT INTO `$tableName`($colName) VALUES($colValue)";
		$statement = $this->pdo->prepare($query);
		$statement->execute();
		$this->writeLog($query, $statement);
		return $this->pdo->lastInsertId() ? $this->pdo->lastInsertId() : $statement->rowCount();
	}

	/**
	 * 执行一条SQL语句
	 *
	 * @param query
	 *
	 * @return
	 */
	public function execute($query)
	{
		$statement = $this->pdo->prepare($query);
		$statement->execute();
		$this->writeLog($query, $statement);

		preg_match("/^([a-z]+)(.+)$/i", $query, $match);

		if (!isset($match[1])) return $statement->fetchAll();
		$match[1] = strtolower($match[1]);

		if ($match[1]=='select') {
			$statement->setFetchMode(PDO::FETCH_ASSOC);
			return $statement->fetchAll();
		}
		elseif ($match[1]=="insert") {
			return $this->pdo->lastInsertId() ? $this->pdo->lastInsertId() : $statement->rowCount();
		}
		elseif ($match[1]=="update" || $match[1]=="delete") {
			return $statement->rowCount();
		}
	}

	/**
	 * 执行联合查询
	 * 
	 * 
	 */ 
	public function getRowBySql($query,$type)
	{
		$arr = array('One','Row','All');

		if (in_array($type,$arr)) {
			$statement = $this->pdo->prepare($query);
			$statement->execute();
			$statement->setFetchMode(PDO::FETCH_ASSOC);
			$this->writeLog($query, $statement);

			if ($type == 'One') {
				return $statement->fetchColumn();
			} elseif ($type == 'Row') {
				return $statement->fetch();
			} else {
				return $statement->fetchAll();
			}
		}
	}

	/**
	 * 输出错误信息
	 *
	 * @return
	 */
	public function writeLog($query, $statement)
	{
		$ch = false;
		$msg = $statement->errorInfo();
		if ($this->querylog==true)
		{
			$query = preg_replace("/[ \f\r\t\n]+/", " ", $query);
			$ch = true;
			@error_log(date('Y-m-d H:i:s') . ': '.$msg[0].','.$msg[1].'Query: ' . $query . "\n", 3, $this->querylogPath);
		}

		if ($this->errorlog==true)
		{
			if ($msg[0] != 0 || (isset($msg[1]) && $msg[1] != null))
			{
				if(!$ch)
					$query = preg_replace("/[ \f\r\t\n]+/", " ", $query);
				$msg = $statement->errorInfo();

				$string = ' -- Time: ' . date('Y-m-d H:i:s') . "\n";
				$string.= ' -- ErrorCode: ' . $msg[0] . "\n";
				$string.= ' -- SpecErrorCode: ' . $msg[1] . "\n";
				$string.= ' -- ErrorMSG: ' . $msg[2] . "\n";
				$string.= ' -- ErrorSQL: ' . $query . "\n\n\n";
				@error_log($string, 3, $this->errorlogPath);
				if($msg[0] != 23000 || !in_array($msg[1], array(1462,1062)))
					SysDie('T_DB', 'E_SQL', $query . "\n" . $msg[0] . ':' .$msg[2]);
			}
		}
	}
}

